package com.cyw.common.utils.web;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

import static com.cyw.common.constants.CommonConstant.CONTENT_TYPE_JSON;


/**
 * @Author: sxw
 * @Date: 2020/9/22
 * @Desc: 缓存请求实体数据，用于多次读取数据,只支持application/json
 */
@Slf4j
public class HttpRequestBodyCacheFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            if (CONTENT_TYPE_JSON.equalsIgnoreCase(httpServletRequest.getContentType())) {
                CachedHttpRequest cachedHttpRequest = new CachedHttpRequest(httpServletRequest);
                chain.doFilter(cachedHttpRequest, response);
                cachedHttpRequest.bytes = null;
                log.debug("cachedHttpRequest bytes clear");
                return;
            }
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }

    public static class CachedHttpRequest extends HttpServletRequestWrapper {

        private byte[] bytes;

        public CachedHttpRequest(HttpServletRequest request) throws IOException {
            super(request);
            ByteArrayOutputStream output = new ByteArrayOutputStream();
            IOUtils.copy(request.getInputStream(), output);
            bytes = output.toByteArray();
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            return new ServletInputStreamWrapper(new ByteArrayInputStream(bytes));
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }

        public byte[] getBytes() {
            return bytes;
        }
    }

    private static class ServletInputStreamWrapper extends ServletInputStream {

        private ByteArrayInputStream bais;

        public ServletInputStreamWrapper(ByteArrayInputStream bais) throws IOException {
            this.bais = bais;
        }

        @Override
        public boolean isFinished() {
            return false;
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setReadListener(ReadListener readListener) {
        }

        @Override
        public int read() throws IOException {
            return bais.read();
        }
    }
}
